import os
import shutil
from natsort import natsorted
import hashlib

def remove_path(path) -> None:
    if os.path.isdir(path):
        shutil.rmtree(path)
    elif os.path.isfile(path):
        os.remove(path)
    else:
        print(f'WARN: {path} not exist, then cannot be removed')

def check_folder_empty(path) -> bool:
    assert os.path.isdir(path)
    sub_list = os.listdir(path)
    return len(sub_list) == 0

def clear_folder(path) -> None:
    assert os.path.isdir(path)
    sub_list = os.listdir(path)
    for sub in sub_list:
        sub_path = os.path.join(path, sub)
        remove_path(sub_path)

def search_file_in_path(path, prefix='', suffix='', remove_pre=False, remove_suf=False, sort=False) -> list:
    """ search files with certain format in path
    :param path: search path
    :param prefix: file's prefix
    :param suffix: file's suffix
    :param remove_pre: remove files' prefix
    :param remove_suf: remove files' suffix
    :param sort: return file names in sorted list
    :return: file names list found in path
    """
    tmp_list = [i for i in os.listdir(path)]
    res_list = []
    for it in tmp_list:
        if it.startswith(prefix) and it.endswith(suffix):
            if remove_pre:
                it = it[len(prefix):]
            if remove_suf:
                it = it[:len(it) - len(suffix)]
            res_list.append(it)
    if sort:
        return natsorted(res_list)
    else:
        return res_list

def md5sum(file) -> str:
    """ return md5sum of given file
    """
    assert os.path.isfile(file)
    with open(file, 'rb') as f:
        return hashlib.md5(f.read()).hexdigest()

def credible_file_copy(src, dst, force=False) -> list:
    """ copy file from of src to dst with check sum
    :param src: path of source file
    :param dst: path of target file no matter if it exists
    :param force: if force writing when dst already exists
    :return unfinished target file list
    """
    assert os.path.isfile(src)
    if not os.path.isfile(dst):
        shutil.copyfile(src, dst)
    elif force and md5sum(src) != md5sum(dst):
        shutil.copyfile(src, dst)
    if md5sum(src) != md5sum(dst):
        return [dst]
    else:
        return []

def credible_copy(src, dst, force=False):
    """ copy file or folder from of src to dst with check sum
    :param src: path of source file or folder
    :param dst: path of target path no matter if it exists
    :param force: if force writing when dst already exists
    :return unfinished target files list
    """
    assert os.path.exists(src)
    error_items = []
    if os.path.isfile(src):
        file_name = src.rstrip().rsplit('/')[-1]
        if os.path.isdir(dst) or dst.rstrip().endswith('/'):
            error_items += credible_file_copy(src, os.path.join(dst, file_name), force)
        else:
            error_items += credible_file_copy(src, dst, force)
    elif os.path.isdir(src):
        folder_name = src.rstrip().rstrip('/').rsplit('/')[-1]
        full_dst = os.path.join(dst, folder_name)
        if not os.path.isdir(full_dst):
            os.makedirs(full_dst)
        for item in os.listdir(src):
            error_items += credible_copy(os.path.join(src, item), full_dst, force)
    else:
        print(f"ERROR: unrecognized source: {src}")
    return error_items
